#include "pp_file.h"
#include "pp_utils.h"

#include <iostream>
#include <cstring>          // memset
#include <stdexcept>        // std::runtime_error

#ifndef _WIN32
#include <sys/stat.h>
#include <dirent.h>
#endif

namespace pp
{
#ifndef _WIN32

#define MAX_PATH 1024

const std::string cur_dir = ".";
const std::string up_dir = "..";

bool is_regular_file(const std::string& name)
{
    struct stat buf;
    if (stat(name.c_str(), &buf) < 0) return false;
    return S_ISREG(buf.st_mode);
}

bool is_directory(const std::string& name)
{
    struct stat buf;
    if (stat(name.c_str(), &buf) < 0) return false;
    return S_ISDIR(buf.st_mode);
}

bool create_directories(const std::string& dirname)
{
    char szCurPath[MAX_PATH];
    size_t llLen;
    const char* szBuf;
    char* s_ptr;
    struct stat oBuf;
    size_t i;
    int iRet;

    if (dirname.empty()) return false;

    /* 路径长度校验 */
    llLen = dirname.length();

    if (llLen >= MAX_PATH) return false;

    memset(szCurPath, 0, sizeof(szCurPath));
    szBuf = dirname.c_str();
    s_ptr = szCurPath;

    for (i = 0; i < llLen; i++)
    {
        if (*szCurPath && (*szBuf == '/' || *szBuf == '\\'))
        {
            iRet = stat(szCurPath, &oBuf);
            if (iRet || (oBuf.st_mode & S_IFMT) != S_IFDIR)
            {
                iRet = mkdir(szCurPath, 0755);
                if (iRet != 0)
                {
                    std::cout << "error to create directory:" << szCurPath << std::endl;
                    return false;
                }
            }
        }
        *s_ptr++ = *szBuf++;
    }
    return true;
}

std::string Path::extension() const
{
    return pp::GetFileExtension(_filename);
}

static void do_recursive_directory_iterator(const std::string& path, std::vector<directory_entry>& entrys)
{
    if (!is_directory(path))
    {
        throw std::runtime_error(path + " is not a directory");
    }

    struct dirent *entry;
    DIR *dir = opendir(path.c_str());

    if (dir == NULL)
    {
        throw std::runtime_error("open dir failed:" + path);
    }

    while ((entry = readdir(dir)) != NULL)
    {
        std::string pn = path + "/" + entry->d_name;

        struct stat statbuf;
        if (stat(pn.c_str(), &statbuf) == -1) continue;

        if (S_ISREG(statbuf.st_mode))
        {
            entrys.push_back(directory_entry(Path(pn)));
        }
        else if (S_ISDIR(statbuf.st_mode) && cur_dir != entry->d_name && up_dir != entry->d_name)
        {
            entrys.push_back(directory_entry(Path(pn)));
            do_recursive_directory_iterator(pn, entrys);
        }
    }
}

std::vector<directory_entry> recursive_directory_iterator(const std::string& path)
{
    std::vector<directory_entry> res;

    do_recursive_directory_iterator(path, res);

    return res;
}

#endif
};
